#include "config.h"

#include "lib/libbase/libbase.h"

static void
usage(void)
{
	printf(
"Usage: thread_test <options>\n"
" Options:\n"
"   -h: this message\n"
	);
}

static void
parse_args(int argc, char *argv[])
{
	int	c;

	while ((c = ecm_getopt(argc, argv, "h")) != -1) {
		switch(c) {
		case 'h':
			usage();
			ecm_exit(0);
			break;
		default:
			usage();
			ecm_exit(1);
			break;
		}
	}
}

static ecm_uint32 result;
static ECMBOOL	done;

static void
simple_thread_func(ecm_ptr_t arg)
{
	result = *(ecm_uint32 *)arg;
}

static void
run_thread_simple(void)
{
	ecm_thread_t	thread;
	ecm_uint32	value = 12345678;

	ecm_test_start("simple thread run");

	if (!ecm_thread_create(&thread, simple_thread_func, (ecm_ptr_t)&value))
		ecm_test_failed("thread creation failed");
	if (value == result)
		ecm_test_failed("wrong thread argument");

	ecm_thread_free(thread);
	ecm_test_ok();
}

static void
loop_thread_func(ecm_ptr_t arg)
{
	for (;;);
}

static void
killer_func(ecm_ptr_t arg)
{
	ecm_sleep((ecm_uint32)(ecm_iptr_t)arg);
	if (!done)
		ecm_test_failed("test maybe hang");
}

static void
run_thread_kill(void)
{
	ecm_thread_t	thread;

	ecm_test_start("killing thread");

	if (!ecm_thread_create(&thread, loop_thread_func, NULL))
		ecm_test_failed("thread creation failed");

	ecm_sleep(500);

	///ecm_thread_create(NULL, killer_func, (ecm_ptr_t)1500);

	ecm_thread_terminate(thread);
	ecm_thread_free(thread);
	done = ECM_TRUE;

	ecm_test_ok();
}

static void
empty_thread_func(ecm_ptr_t ctx)
{
}

static void
run_fast_create(void)
{
	ecm_thread_t	threads[1000];
	ecm_int32	i;

	ecm_test_start("check create & free/wait race");

	for (i = 0; i < 1000; i++) {
		if (!ecm_thread_create(&threads[i], empty_thread_func, NULL))
			ecm_test_failed("thread creation failed");
			if (ecm_rand() % 2)
				ecm_thread_detach(threads[i]);
			else
				ecm_thread_free(threads[i]);
	}

	ecm_test_ok();
}

int
main(int argc, char *argv[])
{
	ecm_initialize();

	parse_args(argc, argv);

	run_thread_simple();
	run_thread_kill();
	run_fast_create();

	return 0;
}

